#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <functional>
#include "Log.hpp"
#include "InetAddr.hpp"


enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    USAGE_ERROE
};

const static int defaultfd=-1;

using func_t =std::function<std::string(const std::string&,bool &ok)>;

class UdpServer
{
public:
    UdpServer(uint16_t port,func_t func)
    :_sockfd(defaultfd),_port(port),_isrunning(false),_func(func)
    {}
    void InitServer()
    {
        //1.创建UDP socket套接字 ---必须要做的
        _sockfd=socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd==-1)
        {
             LOG(FATAL,"socket errot,%s,%d\n",strerror(errno),errno);
             exit(SOCKET_ERROR);
        }
        LOG(INFO,"socket create success,sockfd: %d\n",_sockfd);

        //2.0 填充sockaddr_in结构
        struct sockaddr_in local; 
        // struct sockaddr_in 系统提供的数据类型。local是变量，在用户栈上开辟
        bzero(&local,sizeof(local));//清零结构体的所有字节清零，确保没有残留数据。
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        //将端口号从主机字节序转换为网络字节序，并存储在 sin_port 成员中字符串风格的点分十进制IP地址转成4字节IP
        local.sin_addr.s_addr=INADDR_ANY;
        //将 IP 地址设置为 INADDR_ANY ，表示服务器将监听所有可用的网络接口。

        //bind（绑定） sockfd和网络信息（IP(?)+ Port）
        int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
        if(n<0)
        {
            LOG(FATAL,"bind error,%s,%d\n",strerror(errno),errno);
            exit(BIND_ERROR);
        }
        LOG(INFO,"socket bind success\n");
    }
    void Start()
    {
        //一直运行的
        _isrunning=true;
        while(true)
        {
            char request[1024];
            struct sockaddr_in peer;
            socklen_t len =sizeof(peer);

            //1.让server先收集数据
            ssize_t n=recvfrom(_sockfd,request,sizeof(request)-1,0,(struct sockaddr*)&peer,&len);
            if(n>0)
            {
                request[n]=0;
                InetAddr addr(peer);
                LOG(DEBUG,"get message from [%s:%d]: %s\n",addr.Ip().c_str(),addr.Port(),request);

                bool ok=false;
                std::string response=_func(request,ok);
                //2. 将server收到的数据发回对方
                sendto(_sockfd,response.c_str(),response.size(),0,(struct sockaddr*)&peer,len);
            }
        }
        _isrunning=false;
    }
    ~UdpServer()
    {}
private:
    int _sockfd;
   //std::string _ip; //IP不是必须的
   uint16_t _port;//端口号
   bool _isrunning;
   func_t _func;
};